/**
 * @file   : demo.c
 * @author : chenshucheng
 * @date   : 03/24/2021
 * @brief  : 测试demo
 * @note   : 创建文件
 */
#include <stdlib.h>
#include "init.h"

S32 fwtIntroTstInit(void)
{
    return 0;
}

S32 fwtIntroTstClean(void)
{
    return 0;
}
/**
 * @brief   交换两个数
 * @param:  [in]   *S32  操作数a
 *          [in]   *S32  操作数b
 * @return  [out]  无
 */
void exchangeTwoNum(S32 *a, S32 *b)
{
    S32 temp;
    temp = *a;
    *a = *b;
    *b = temp;
    return;
}

/**
 * @brief   Module 01 exercise 1-16
 *          试写一算法，自大至小依次输出顺序读入的三个整数X，Y，Z的值
 * @param:  [in]   无
 * @return  [out]  无
 * @algorithm
 *          算法一（冒泡法）：
 *          1. 比较X和Y，如果X<Y，交换X和Y
 *          2. 比较后两个，例如是Y和Z，如果Y<Z，交换Y和Z，此时最后一个一定是最小的
 *          3. 再用前边的方法选出次小的放到倒数第二个位置，结束
 *          分析：改算法需要进行三次比较，最坏情况需要进行9次赋值（每交换一次需要三次赋值）
 *          算法二（穷举法）（不给出程序）：
 *          分析：理论上讲，三次比较不可以减少，最坏情况下，即三个数字均需要改变位置时，需要移动4次
 *          x最大，y第二，z第三，（x>=y, y>=z），                        不用移动
 *          x最大，y第三，z第二，（x>=y, y< z, x>=z       ），           交换y和z
 *          x第二，y最大，z第三，（x< y        ,   x>=z），              交换x和y
 *          x第二，y第三，z最大，（x>=y, y< z, x< z）,                  z移动到最前边
 *          x最小，y最大，z第二，（x< y, x< z, y>=z）,                  x移动到最后边
 *          x最小，y第二，z最大，（x< y, x< z, y< z）,                  交换x和z
 */
S32 exM01Ex16Reorder(S32 *x, S32 *y, S32 *z)
{
    if ((NULL == x)||(NULL == y)||(NULL == z)) {
        return -FAILED;
    }
    if (*x < *y) {
        exchangeTwoNum(x, y);
    }
    if (*y < *z) {
        exchangeTwoNum(y, z);
    }
    if (*x < *y) {
        exchangeTwoNum(x, y);
    }
    return SUCCESS;
}

void testM01Ex16Reorder(void)
{
    S32 rc = -FAILED;
    S32 x = 0, y = 0, z = 0;
    
    rc = exM01Ex16Reorder(NULL, 0, 0);
    CU_ASSERT_EQUAL(-FAILED, rc);

    x = 3, y = 2, z = 1;
    printf("Before x = %d, y = %d, z = %d\n", x, y ,z);
    rc = exM01Ex16Reorder(&x, &y, &z);
    printf("After x = %d, y = %d, z = %d\n\n", x, y, z);
    CU_ASSERT(x >= y);
    CU_ASSERT(y >= z);

    x = 3, y = 1, z = 2;
    printf("Before x = %d, y = %d, z = %d\n", x, y ,z);
    rc = exM01Ex16Reorder(&x, &y, &z);
    printf("After x = %d, y = %d, z = %d\n\n", x, y, z);
    CU_ASSERT(x >= y);
    CU_ASSERT(y >= z);

    x = 2, y = 3, z = 1;
    printf("Before x = %d, y = %d, z = %d\n", x, y ,z);
    rc = exM01Ex16Reorder(&x, &y, &z);
    printf("After x = %d, y = %d, z = %d\n\n", x, y, z);
    CU_ASSERT(x >= y);
    CU_ASSERT(y >= z);

    x = 2, y = 1, z = 3;
    printf("Before x = %d, y = %d, z = %d\n", x, y ,z);
    rc = exM01Ex16Reorder(&x, &y, &z);
    printf("After x = %d, y = %d, z = %d\n\n", x, y, z);
    CU_ASSERT(x >= y);
    CU_ASSERT(y >= z);

    x = 1, y = 3, z = 2;
    printf("Before x = %d, y = %d, z = %d\n", x, y ,z);
    rc = exM01Ex16Reorder(&x, &y, &z);
    printf("After x = %d, y = %d, z = %d\n\n", x, y, z);
    CU_ASSERT(x >= y);
    CU_ASSERT(y >= z);

    x = 1, y = 2, z = 3;
    printf("Before x = %d, y = %d, z = %d\n", x, y ,z);
    rc = exM01Ex16Reorder(&x, &y, &z);
    printf("After x = %d, y = %d, z = %d\n\n", x, y, z);
    CU_ASSERT(x >= y);
    CU_ASSERT(y >= z);
    return;
}
/**
 * @brief   Module 01 exercise 1-17
 *          试编写求k阶斐波那契数列的第m项值的函数算法，k和m均以值调用的形式在函数参数表中出现
 * @param:  [in]    S32     数列阶数k
 *          [in]    S32     项数m
 * @return  [out]  无
 */
S32 exM01Ex17Fibonacci(S32 k, S32 m, S32 *fm)
{
    S32 rc = FAILED;
    S32 *fArr = NULL;
    S32 len = 0;
    S32 i = 0, j = 0;
    
    ///< 1. 入参检查
    if ((k <= 0)||(m < 0)) {
        goto lEnd;
    }

    ///< 2. 申请空间
    len = MAX(k, m+1);
    fArr = malloc(len * sizeof(S32));
    if (NULL == fArr) {
        printf("malloc fail\n");
        goto lEnd;
    }
    memset(fArr, 0, len*sizeof(S32));

    ///< 3. 赋初值
    fArr[k-1] = 1; ///< 前k-2项是0，第k-1项是1

    ///< 4. 循环求值
    ///< 4.1 从第k项开始满足求值公式，一直求到第Len项
    for (i = k; i < len; i++) {
        fArr[i] = 0;///< 清理一下内存
        ///< 4.2 对于k阶数列，第n项等于前边k项的和
        for (j = 1; j <= k; j++) {
            fArr[i] += fArr[i-j];
        }
    }

    ///< 5. 找到第m项
    *fm = fArr[m];
    free(fArr);
    fArr = NULL;
    rc = SUCCESS;
    
lEnd:
    return rc;
}

void testM01Ex17Fibonacci(void)
{
    S32 rc = FAILED;
    S32 k = 0, m = 0, fm = 0;

    k = 1, m = 1;
    printf("\n\nk = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 1);
    printf("fm = %d\n\n", fm);

    k = 1, m = 5;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 1);
    printf("fm = %d\n\n", fm);

    k = 2, m = 1;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 1);
    printf("fm = %d\n\n", fm);

    k = 2, m = 5;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 5);
    printf("fm = %d\n\n", fm);

    k = 2, m = 10;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 55);
    printf("fm = %d\n\n", fm);

    k = 3, m = 0;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 0);
    printf("fm = %d\n\n", fm);

    k = 3, m = 2;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 1);
    printf("fm = %d\n\n", fm);

    k = 3, m = 7;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 13);
    printf("fm = %d\n\n", fm);

    k = 4, m = 2;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 0);
    printf("fm = %d\n\n", fm);

    k = 4, m = 8;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 15);
    printf("fm = %d\n\n", fm);

    k = 4, m = 10;
    printf("k = %d, m = %d\n", k, m);
    rc = exM01Ex17Fibonacci(k, m, &fm);
    CU_ASSERT_EQUAL(rc, SUCCESS);
    CU_ASSERT_EQUAL(fm, 56);
    printf("fm = %d\n\n", fm);

    return;
}

CU_TestInfo gFwtIntroTstCases[] = {
{   "M01-ex-16Reorder",         testM01Ex16Reorder,         },
{   "M01-ex-17Fibonacci",       testM01Ex17Fibonacci,},
    CU_TEST_INFO_NULL,
};

CU_SuiteInfo gFwtIntroSuites[] = {
    {
        "M01Introduction",fwtIntroTstInit,fwtIntroTstClean,gFwtIntroTstCases
    },
    CU_SUITE_INFO_NULL,
};

/**
 * @brief   将测试套件注册到gUtSuites数组中，注意该数组的最后一个元素必须为空
 * @param:  [in]   无
 * @return  [out]  无
 * @warning 可重入
 * @note    新生成函数
 */
static void utFwtIntroduction(void)
{
    fwtInitSuite(gFwtIntroSuites);
    
    return ;
}

UITEINIT(utFwtIntroduction)

